package cn.edu.sjtu.gateway.handler;

import cn.edu.sjtu.gateway.dto.LoginDTO;
import cn.edu.sjtu.gateway.dto.TokenDTO;
import cn.edu.sjtu.gateway.model.RespStatus;
import cn.edu.sjtu.gateway.model.Result;
import cn.edu.sjtu.gateway.model.User;
import cn.edu.sjtu.gateway.util.JWTUtil;
import cn.edu.sjtu.gateway.util.ResultUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import java.util.List;

import static java.util.Objects.requireNonNull;

@Component
public class UserHandler {

    @Value("${auth.authUrl}")
    private String authUrl;

    public Mono<ServerResponse> auth(final ServerRequest request) {
        final WebClient client = WebClient.create(authUrl);
        ParameterizedTypeReference<Result<List<User>>> typeRef = new ParameterizedTypeReference<Result<List<User>>>() {
        };
        return request.bodyToMono(LoginDTO.class)
                // validation
                .doOnNext(userLoginRequest -> {
                    requireNonNull(userLoginRequest.getUserId());
                    requireNonNull(userLoginRequest.getPassword());
                })
                // query for user
                .flatMap(userLoginRequest ->
                        client.get().uri(uriBuilder ->
                                uriBuilder
                                        .queryParam("userId", userLoginRequest.getUserId())
                                        .queryParam("password", userLoginRequest.getPassword())
                                        .build())
                                .accept(MediaType.APPLICATION_JSON)
                                .exchange()
                )
                // transform response to result
                .flatMap(response -> response.bodyToMono(typeRef))
                .map(Result::getData)
                .map(list -> list.get(0))
                .map(JWTUtil::encode)
                .map(TokenDTO::new)
                .map(ResultUtil::success)
                .flatMap(result -> ServerResponse.ok()
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(Mono.just(result), Result.class))
                .onErrorResume(ex -> ServerResponse.badRequest()
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(Mono.just(ResultUtil.error(RespStatus.WRONG_PASSWORD)), Result.class));
    }
}
